package com.yishe.redis;

import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisConnectionUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.data.redis.support.atomic.RedisAtomicLong;
import org.springframework.util.StringUtils;

import java.io.Serializable;
import java.util.Date;
import java.util.Set;
import java.util.concurrent.TimeUnit;


@Slf4j
public class RedisUtils { 

	public static final String regionDefault = "YISHE";

	private static RedisUtils redisUtils;

	private RedisTemplate<Serializable, Object> redisTemplate;


	public void setRedisTemplate(RedisTemplate<Serializable, Object> redisTemplate) {
		this.redisTemplate = redisTemplate;
	}

	public static RedisUtils getInstance() {
		if (null == redisUtils) {
			synchronized (RedisUtils.class) {
				if (null == redisUtils) {
					log.info("缓存实例为空，初始化开始...");
					redisUtils = new RedisUtils();
					log.info("缓存实例为空，初始化完成...");
				}
			}
		}
		return redisUtils;
	}
 

	public Object get(String region, String key) {
		try {
			String factKey = this.getKeyName(region, key);
			ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
			return operations.get(factKey);
		} catch (Exception e) {
			log.error("根据region[{}],key[{}]获取缓存时异常!", region, key);
			e.printStackTrace();
		} finally {
			RedisConnectionUtils.unbindConnection(redisTemplate.getConnectionFactory());
		}
		return null;
	}
 
	public Object get(String key) {
		return this.get(regionDefault, key);
	}
 

	/**
	 * 设置缓存（永不过期）
	 * @param region 缓存块名称（注意命名规范）
	 * @param key 缓存key
	 * @param value 缓存值 
	 */
	public void set(String region, String key, Object value) {
		try {
			if (!StringUtils.isEmpty(key)) {
				String factKey = this.getKeyName(region, key);
				ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
				operations.set(factKey, value);
			}
		} catch (Exception e) {
			log.error("根据region[{}],key[{}]存储缓存时异常!", region, key);
			e.printStackTrace();
		} finally {
			RedisConnectionUtils.unbindConnection(redisTemplate.getConnectionFactory());
		}
	}

	/**
	 * 设置缓存
	 * @param region 缓存块名称（注意命名规范）
	 * @param key 缓存key
	 * @param value 缓存值
	 * @param expireTime 到期时间（单位：秒）
	 */
	public void set(String region, String key, Object value, int expireTime) {
		try {
			if (!StringUtils.isEmpty(key)) {
				String factKey = this.getKeyName(region, key);
				ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
				operations.set(factKey, value);
				redisTemplate.expire(factKey, expireTime, TimeUnit.SECONDS);
			}
		} catch (Exception e) {
			log.error("根据region[{}],key[{}]存储缓存时异常!", region, key);
			e.printStackTrace();
		} finally {
			RedisConnectionUtils.unbindConnection(redisTemplate.getConnectionFactory());
		}
	}

	/**
	 * 设置缓存 （使用默认块）
	 * @param key 缓存key
	 * @param value 缓存值 
	 */
	public void set(String key, Object value) {
		this.set(regionDefault, key, value);
	}

	/**
	 * 设置缓存
	 * @param key 缓存key
	 * @param value 缓存值
	 * @param expireTime 到期时间（单位：秒）
	 */
	public void set(String key, Object value, int expireTime) {
		try {
			String factKey = this.getKeyName(regionDefault, key);
			ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
			operations.set(factKey, value);
			redisTemplate.expire(factKey, expireTime, TimeUnit.SECONDS);
		} catch (Exception e) {
			log.error("根据key[{}],expireTime[{}]存储缓存时异常!", key, expireTime);
			e.printStackTrace();
		} finally {
			RedisConnectionUtils.unbindConnection(redisTemplate.getConnectionFactory());
		}
	}
 
	/**
	 * 获取全部keys信息
	 * @param pattern
	 * @return
	 */
	public Set<Serializable> keys(String pattern) {
		try {
			return redisTemplate.keys(pattern);
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		} finally {
			RedisConnectionUtils.unbindConnection(redisTemplate.getConnectionFactory());
		}
	}

	/**
	 * 删除缓存
	 * @param region 缓存块
	 * @param key 键
	 */
	public void remove(String region, String key) {
		try {
			String factKey = this.getKeyName(region, key);
			if (exists(factKey)) {
				redisTemplate.delete(factKey);
			}
		} catch (Exception e) {
			log.error("根据region[{}],key[{}]清理缓存时异常!", region, key);
			e.printStackTrace();
		} finally {
			RedisConnectionUtils.unbindConnection(redisTemplate.getConnectionFactory());
		}
	} 
	
	/**
	 * 根据默认块+key删除缓存
	 * @param key
	 */
	public void remove(String key) {
		try {
			String factKey = this.getKeyName(regionDefault, key);
			if (exists(factKey)) {
				redisTemplate.delete(factKey);
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			RedisConnectionUtils.unbindConnection(redisTemplate.getConnectionFactory());
		}
	}
 
	private boolean exists(String key) {
		try {
			return redisTemplate.hasKey(key);
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			RedisConnectionUtils.unbindConnection(redisTemplate.getConnectionFactory());
		}
		return false;
	}
	
	/**
	 * 根据前缀key模糊匹配清理缓存对象信息
	 * @param prefix
	 */
	public void clearAllStartingWith(String prefix) {
		try {
			Set<Serializable> setData = this.keys(prefix);
			if (null != setData) {
				redisTemplate.delete(setData);
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			RedisConnectionUtils.unbindConnection(redisTemplate.getConnectionFactory());
		}
	}
 

	/**
	 * 生成缓存的 key
	 * 
	 * @param region
	 * @param key
	 * @return
	 */
	@SuppressWarnings("rawtypes")
	protected String getKeyName(String region, Object key) {
		if (StringUtils.isEmpty(region)) {
			region = regionDefault;
		}
		if (key instanceof Number) {
			return region + ":E:" + key;
		} else {
			Class keyClass = key.getClass();
			if (String.class.equals(keyClass) || StringBuffer.class.equals(keyClass)
					|| StringBuilder.class.equals(keyClass)) {
				return region + ":Y:" + key;
			}
		}
		return region + ":M:" + key;
	}
	

	public long generate( ) {
		RedisAtomicLong redisAtomicLong = new RedisAtomicLong(new Date().toString(), redisTemplate.getConnectionFactory());
		return redisAtomicLong.incrementAndGet();
	}
	public long generate(String key) {
		
		RedisAtomicLong redisAtomicLong = new RedisAtomicLong(key, redisTemplate.getConnectionFactory());
		return redisAtomicLong.incrementAndGet();
	}

	public long generate(String key,Date expireTime) {
		RedisAtomicLong redisAtomicLong = new RedisAtomicLong(key, redisTemplate.getConnectionFactory());
		redisAtomicLong.expireAt(expireTime);
		return redisAtomicLong.incrementAndGet();
	}

	public long generate(String key,int increment) {
		RedisAtomicLong redisAtomicLong = new RedisAtomicLong(key, redisTemplate.getConnectionFactory());
		return redisAtomicLong.addAndGet(increment);
	}
	public long generate(String key,int increment,Date expireTime) {
		RedisAtomicLong redisAtomicLong = new RedisAtomicLong(key, redisTemplate.getConnectionFactory());
		redisAtomicLong.expireAt(expireTime);
		return redisAtomicLong.addAndGet(increment);
	}

    /**
     * 
    * getRedisTemplate:(获取缓存模板). <br/>
    * TODO(这里描述这个方法的注意事项 – 可选).<br/>
    *
    * @author 蒋万勇 
    * @since 2020-08-17
     */
    public RedisTemplate<Serializable, Object> getRedisTemplate() {
        return redisTemplate;
    }
	
}